<template>
  <div class="app-container">
    <!-- 音量可视化画布 -->
    <canvas
      ref="visualizerCanvas"
      class="visualizer"
      :width="canvasWidth"
      :height="canvasHeight"
    ></canvas>

    <!-- 控制按钮 -->
    <div class="controls">
      <button @click="toggleRecording" :disabled="isRecording">
        {{ isRecording ? '停止录音' : '开始录音' }}
      </button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      audioContext: null,
      analyser: null,
      source: null,
      stream: null,
      isRecording: false,
      canvasWidth: 600,
      canvasHeight: 200,
      dataArray: null,
      animationFrameId: null,
    };
  },

  mounted() {
    this.initCanvas();
  },

  beforeDestroy() {
    this.stopRecording();
  },

  methods: {
    // 初始化画布和音频上下文
    async initCanvas() {
      try {
        // 获取画布上下文
        this.ctx = this.$refs.visualizerCanvas.getContext('2d');

        // 初始化音频上下文
        this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
        this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        this.source = this.audioContext.createMediaStreamSource(this.stream);
        this.analyser = this.audioContext.createAnalyser();

        // 配置分析器
        this.analyser.fftSize = 2048;
        this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
        this.source.connect(this.analyser);
        this.analyser.connect(this.audioContext.destination);
      } catch (error) {
        console.error('无法访问麦克风:', error);
      }
    },

    // 开始/停止录音
    toggleRecording() {
      if (this.isRecording) {
        this.stopRecording();
      } else {
        this.startRecording();
      }
    },

    // 开始录音并开始绘制
    startRecording() {
      this.isRecording = true;
      this.draw();
    },

    // 停止录音并清理资源
    stopRecording() {
      this.isRecording = false;
      this.animationFrameId && cancelAnimationFrame(this.animationFrameId);
      this.stream?.getTracks().forEach((track) => track.stop());
      this.audioContext?.close();
      this.dataArray = null;
    },

    // 绘制音量可视化效果
    draw() {
      if (!this.isRecording) return;

      // 获取当前音频数据
      this.analyser.getByteFrequencyData(this.dataArray);

      // 清空画布
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
      this.ctx.fillStyle = '#409EFF';

      // 计算每个柱子的宽度和间距
      const barWidth = (this.canvasWidth / this.dataArray.length) * 2;
      const spacing = 1;
      let x = 0;

      // 绘制柱状图
      this.dataArray.forEach((value) => {
        const barHeight = (value / 255) * this.canvasHeight; // 映射到0-100%
        this.ctx.fillRect(x, this.canvasHeight - barHeight, barWidth, barHeight);
        x += barWidth + spacing;
      });

      // 循环调用绘制
      this.animationFrameId = requestAnimationFrame(() => this.draw());
    },
  },
};
</script>

<style scoped>
.app-container {
  text-align: center;
  margin-top: 50px;
}

.visualizer {
  border: 1px solid #409eff;
  border-radius: 8px;
  background: #1a1a1a;
}

.controls {
  margin-top: 20px;
}

button {
  padding: 10px 20px;
  background: #409eff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:disabled {
  background: #cccccc;
  cursor: not-allowed;
}
</style>